package org.finesys.common.sensitive.core.seriallizer;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Objects;

import org.finesys.common.sensitive.core.annotation.base.SensitiveInfo;
import org.finesys.common.sensitive.core.handler.base.SensitiveHandler;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.Getter;
import lombok.Setter;

/**
 * 敏感信息脱敏序列化
 */
@Getter
@Setter
public class SensitiveInfoSerialize extends JsonSerializer<String> implements ContextualSerializer {

	private SensitiveHandler sensitiveHandler;

	@Override
	public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {

		if (!StringUtils.hasText(value)) {
			gen.writeNull();
			return;
		}
		// 获取序列化字段
		String currentName = gen.getOutputContext().getCurrentName();
		Object currentValue = gen.getCurrentValue();
		Class<?> currentValueClass = currentValue.getClass();
		Field field = ReflectUtil.getField(currentValueClass, currentName);
		SensitiveInfo[] sensitiveInfos = AnnotationUtil.getCombinationAnnotations(field, SensitiveInfo.class);
		if (ArrayUtil.isEmpty(sensitiveInfos)) {
			gen.writeString(value);
			return;
		}
		for (Annotation sensitiveInfo : sensitiveInfos) {
			if (AnnotationUtil.hasAnnotation(sensitiveInfo.annotationType(), SensitiveInfo.class)) {
				value = sensitiveHandler.desensitize(value, sensitiveInfo);
				gen.writeString(value);
				return;
			}
		}
		gen.writeString(value);
	}

	@Override
	public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
			throws JsonMappingException {
		if (Objects.isNull(property)) {
			return prov.findNullValueSerializer(null);
		}
		// 非String类型直接跳过
		if (!Objects.equals(property.getType().getRawClass(), String.class)) {
			return prov.findValueSerializer(property.getType(), property);
		}
		SensitiveInfo sensitiveInfo = property.getAnnotation(SensitiveInfo.class);
		if (Objects.isNull(sensitiveInfo)) {
			sensitiveInfo = property.getContextAnnotation(SensitiveInfo.class);
		}
		if (Objects.isNull(sensitiveInfo)) {
			return prov.findValueSerializer(property.getType(), property);
		}
		SensitiveInfoSerialize serialize = new SensitiveInfoSerialize();
		serialize.setSensitiveHandler(Singleton.get(sensitiveInfo.handler()));
		return serialize;
	}

}
